// This source is subject to the Microsoft Public License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.IO;
using System.Windows.Forms;
using System.Xml;

using Infragistics.Win.UltraWinTree;

namespace QuoteAdvantageEditor
{
	/// <summary>
	/// Screen for specifying child products and configuration rules
	/// </summary>
   public class ProductCustomizeDlg : System.Windows.Forms.Form
   {
      private Product   objProduct;
      private string    m_strRuleFileNameFullPath = "";
      private string    m_strRuleFileName = "";
      private AuthoringEngine eng = null;
      private XmlNode   nodeRuleFileRoot = null;
      private bool      bNeedSave = false;


      private System.Windows.Forms.Button btnOK;
      private System.Windows.Forms.Button btnCancel;
      private System.Windows.Forms.Label label2;
      private System.Windows.Forms.ImageList imageListTree;
      private System.Windows.Forms.Label lblRuleFileName;
      private System.Windows.Forms.Label label3;
      private System.Windows.Forms.Label lblProductName;
      private Infragistics.Win.UltraWinTree.UltraTree ctlTree;
      private System.Windows.Forms.Button btnAdd;
      private System.Windows.Forms.Button btnModify;
      private System.Windows.Forms.ContextMenu mnuTreeList;
      private System.Windows.Forms.MenuItem menuItem15;
      private System.Windows.Forms.MenuItem menuItem11;
      private System.Windows.Forms.MenuItem mnuModify;
      private System.Windows.Forms.Button btnRemove;
      private System.Windows.Forms.MenuItem mnuAdd;
      private System.Windows.Forms.MenuItem mnuRemove;
      private System.Windows.Forms.MenuItem mnuMoveUp;
      private System.Windows.Forms.MenuItem mnuMoveDown;
      private System.Windows.Forms.MenuItem mnuNestedItems;
      private System.ComponentModel.IContainer components;


      public Product ParentProduct
      {
         get { return objProduct; }
         set { objProduct = value; }
      }

      public string RuleFileName
      {
         get { return m_strRuleFileNameFullPath; }
         set 
         { 
            m_strRuleFileNameFullPath = value; 

            FileInfo info = new FileInfo(m_strRuleFileNameFullPath);
            m_strRuleFileName = info.Name;
         }
      }

      public AuthoringEngine Engine
      {
         get { return eng; }
         set { eng = value; }
      }

      public ProductCustomizeDlg()
      {
         //
         // Required for Windows Form Designer support
         //
         InitializeComponent();

         //
         // TODO: Add any constructor code after InitializeComponent call
         //
      }

      /// <summary>
      /// Clean up any resources being used.
      /// </summary>
      protected override void Dispose( bool disposing )
      {
         if( disposing )
         {
            if(components != null)
            {
               components.Dispose();
            }
         }
         base.Dispose( disposing );
      }

      #region Windows Form Designer generated code
      /// <summary>
      /// Required method for Designer support - do not modify
      /// the contents of this method with the code editor.
      /// </summary>
      private void InitializeComponent()
      {
         this.components = new System.ComponentModel.Container();
         Infragistics.Win.UltraWinTree.UltraTreeColumnSet ultraTreeColumnSet1 = new Infragistics.Win.UltraWinTree.UltraTreeColumnSet();
         Infragistics.Win.UltraWinTree.Override _override1 = new Infragistics.Win.UltraWinTree.Override();
         System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(ProductCustomizeDlg));
         this.btnOK = new System.Windows.Forms.Button();
         this.btnCancel = new System.Windows.Forms.Button();
         this.label2 = new System.Windows.Forms.Label();
         this.lblRuleFileName = new System.Windows.Forms.Label();
         this.btnAdd = new System.Windows.Forms.Button();
         this.ctlTree = new Infragistics.Win.UltraWinTree.UltraTree();
         this.mnuTreeList = new System.Windows.Forms.ContextMenu();
         this.mnuModify = new System.Windows.Forms.MenuItem();
         this.mnuNestedItems = new System.Windows.Forms.MenuItem();
         this.menuItem15 = new System.Windows.Forms.MenuItem();
         this.mnuAdd = new System.Windows.Forms.MenuItem();
         this.mnuRemove = new System.Windows.Forms.MenuItem();
         this.menuItem11 = new System.Windows.Forms.MenuItem();
         this.mnuMoveUp = new System.Windows.Forms.MenuItem();
         this.mnuMoveDown = new System.Windows.Forms.MenuItem();
         this.imageListTree = new System.Windows.Forms.ImageList(this.components);
         this.label3 = new System.Windows.Forms.Label();
         this.lblProductName = new System.Windows.Forms.Label();
         this.btnModify = new System.Windows.Forms.Button();
         this.btnRemove = new System.Windows.Forms.Button();
         ((System.ComponentModel.ISupportInitialize)(this.ctlTree)).BeginInit();
         this.SuspendLayout();
         // 
         // btnOK
         // 
         this.btnOK.Location = new System.Drawing.Point(384, 488);
         this.btnOK.Name = "btnOK";
         this.btnOK.Size = new System.Drawing.Size(80, 23);
         this.btnOK.TabIndex = 8;
         this.btnOK.Text = "OK";
         this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
         // 
         // btnCancel
         // 
         this.btnCancel.Location = new System.Drawing.Point(472, 488);
         this.btnCancel.Name = "btnCancel";
         this.btnCancel.Size = new System.Drawing.Size(80, 23);
         this.btnCancel.TabIndex = 9;
         this.btnCancel.Text = "Cancel";
         this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
         // 
         // label2
         // 
         this.label2.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
         this.label2.Location = new System.Drawing.Point(8, 32);
         this.label2.Name = "label2";
         this.label2.Size = new System.Drawing.Size(88, 16);
         this.label2.TabIndex = 2;
         this.label2.Text = "Rule File Name:";
         this.label2.TextAlign = System.Drawing.ContentAlignment.TopRight;
         // 
         // lblRuleFileName
         // 
         this.lblRuleFileName.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
         this.lblRuleFileName.Location = new System.Drawing.Point(96, 32);
         this.lblRuleFileName.Name = "lblRuleFileName";
         this.lblRuleFileName.Size = new System.Drawing.Size(432, 16);
         this.lblRuleFileName.TabIndex = 3;
         this.lblRuleFileName.Text = "MyRuleFile.xml";
         // 
         // btnAdd
         // 
         this.btnAdd.Location = new System.Drawing.Point(8, 488);
         this.btnAdd.Name = "btnAdd";
         this.btnAdd.Size = new System.Drawing.Size(90, 23);
         this.btnAdd.TabIndex = 5;
         this.btnAdd.Text = "Add";
         this.btnAdd.Click += new System.EventHandler(this.btnAdd_Click);
         // 
         // ctlTree
         // 
         this.ctlTree.ColumnSettings.RootColumnSet = ultraTreeColumnSet1;
         this.ctlTree.ContextMenu = this.mnuTreeList;
         this.ctlTree.Font = new System.Drawing.Font("Tahoma", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
         this.ctlTree.HideSelection = false;
         this.ctlTree.ImageList = this.imageListTree;
         this.ctlTree.Location = new System.Drawing.Point(8, 56);
         this.ctlTree.Name = "ctlTree";
         _override1.NodeDoubleClickAction = Infragistics.Win.UltraWinTree.NodeDoubleClickAction.None;
         _override1.SelectionType = Infragistics.Win.UltraWinTree.SelectType.Single;
         this.ctlTree.Override = _override1;
         this.ctlTree.Size = new System.Drawing.Size(544, 424);
         this.ctlTree.TabIndex = 4;
         this.ctlTree.Click += new System.EventHandler(this.ctlTree_Click);
         this.ctlTree.DoubleClick += new System.EventHandler(this.ctlTree_DoubleClick);
         // 
         // mnuTreeList
         // 
         this.mnuTreeList.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
                                                                                    this.mnuModify,
                                                                                    this.mnuNestedItems,
                                                                                    this.menuItem15,
                                                                                    this.mnuAdd,
                                                                                    this.mnuRemove,
                                                                                    this.menuItem11,
                                                                                    this.mnuMoveUp,
                                                                                    this.mnuMoveDown});
         this.mnuTreeList.Popup += new System.EventHandler(this.mnuTreeList_Popup);
         // 
         // mnuModify
         // 
         this.mnuModify.Index = 0;
         this.mnuModify.Text = "Modify...";
         this.mnuModify.Click += new System.EventHandler(this.mnuModify_Click);
         // 
         // mnuNestedItems
         // 
         this.mnuNestedItems.Index = 1;
         this.mnuNestedItems.Text = "Nested Items...";
         this.mnuNestedItems.Click += new System.EventHandler(this.mnuNestedItems_Click);
         // 
         // menuItem15
         // 
         this.menuItem15.Index = 2;
         this.menuItem15.Text = "-";
         // 
         // mnuAdd
         // 
         this.mnuAdd.Index = 3;
         this.mnuAdd.Text = "Add";
         this.mnuAdd.Click += new System.EventHandler(this.mnuAdd_Click);
         // 
         // mnuRemove
         // 
         this.mnuRemove.Index = 4;
         this.mnuRemove.Text = "Remove";
         this.mnuRemove.Click += new System.EventHandler(this.mnuRemove_Click);
         // 
         // menuItem11
         // 
         this.menuItem11.Index = 5;
         this.menuItem11.Text = "-";
         // 
         // mnuMoveUp
         // 
         this.mnuMoveUp.Index = 6;
         this.mnuMoveUp.Text = "Move Up";
         this.mnuMoveUp.Click += new System.EventHandler(this.mnuMoveUp_Click);
         // 
         // mnuMoveDown
         // 
         this.mnuMoveDown.Index = 7;
         this.mnuMoveDown.Text = "Move Down";
         this.mnuMoveDown.Click += new System.EventHandler(this.mnuMoveDown_Click);
         // 
         // imageListTree
         // 
         this.imageListTree.ImageSize = new System.Drawing.Size(16, 16);
         this.imageListTree.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageListTree.ImageStream")));
         this.imageListTree.TransparentColor = System.Drawing.Color.Transparent;
         // 
         // label3
         // 
         this.label3.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
         this.label3.Location = new System.Drawing.Point(8, 8);
         this.label3.Name = "label3";
         this.label3.Size = new System.Drawing.Size(88, 16);
         this.label3.TabIndex = 0;
         this.label3.Text = "Parent Product:";
         this.label3.TextAlign = System.Drawing.ContentAlignment.TopRight;
         // 
         // lblProductName
         // 
         this.lblProductName.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
         this.lblProductName.Location = new System.Drawing.Point(96, 8);
         this.lblProductName.Name = "lblProductName";
         this.lblProductName.Size = new System.Drawing.Size(424, 16);
         this.lblProductName.TabIndex = 1;
         this.lblProductName.Text = "This is my product";
         // 
         // btnModify
         // 
         this.btnModify.Location = new System.Drawing.Point(104, 488);
         this.btnModify.Name = "btnModify";
         this.btnModify.Size = new System.Drawing.Size(90, 23);
         this.btnModify.TabIndex = 6;
         this.btnModify.Text = "Modify";
         this.btnModify.Click += new System.EventHandler(this.btnModify_Click);
         // 
         // btnRemove
         // 
         this.btnRemove.Location = new System.Drawing.Point(200, 488);
         this.btnRemove.Name = "btnRemove";
         this.btnRemove.Size = new System.Drawing.Size(90, 23);
         this.btnRemove.TabIndex = 7;
         this.btnRemove.Text = "Remove";
         this.btnRemove.Click += new System.EventHandler(this.btnRemove_Click);
         // 
         // ProductCustomizeDlg
         // 
         this.AcceptButton = this.btnOK;
         this.AutoScaleBaseSize = new System.Drawing.Size(5, 14);
         this.ClientSize = new System.Drawing.Size(562, 520);
         this.Controls.Add(this.btnRemove);
         this.Controls.Add(this.btnModify);
         this.Controls.Add(this.lblProductName);
         this.Controls.Add(this.label3);
         this.Controls.Add(this.ctlTree);
         this.Controls.Add(this.btnAdd);
         this.Controls.Add(this.lblRuleFileName);
         this.Controls.Add(this.label2);
         this.Controls.Add(this.btnCancel);
         this.Controls.Add(this.btnOK);
         this.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
         this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
         this.MaximizeBox = false;
         this.MinimizeBox = false;
         this.Name = "ProductCustomizeDlg";
         this.ShowInTaskbar = false;
         this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
         this.Text = "Child Product List";
         this.Load += new System.EventHandler(this.ProductCustomizeDlg_Load);
         ((System.ComponentModel.ISupportInitialize)(this.ctlTree)).EndInit();
         this.ResumeLayout(false);

      }
      #endregion

      private void ProductCustomizeDlg_Load(object sender, System.EventArgs e)
      {
         Cursor oldCursor = Cursor.Current;
         Cursor.Current = Cursors.WaitCursor; 

         lblRuleFileName.Text = m_strRuleFileName;
         lblProductName.Text = objProduct.Name;

         nodeRuleFileRoot = eng.LoadChildProductCategoryList(m_strRuleFileNameFullPath);
         RefreshTree();

         if (ctlTree.Nodes.Count > 0)
            ctlTree.Nodes[0].Selected = true;

         EnableControls();
         Cursor.Current = oldCursor; 
      }

      private void btnOK_Click(object sender, System.EventArgs e)
      {
         if (bNeedSave)
         {
            DialogResult result = MessageBox.Show(this, "Save Changes to " + m_strRuleFileName + "?", "QuoteAdvantage Editor", MessageBoxButtons.YesNoCancel);

            if (result == DialogResult.Yes)
            {
               Cursor oldCursor = Cursor.Current;
               Cursor.Current = Cursors.WaitCursor; 
            
               FileInfo objInfo = new FileInfo(m_strRuleFileNameFullPath);
         
               if ((objInfo.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
               {
                  MessageBox.Show(this, "Unable to save. The rule file is read-only.", "QuoteAdvantage Editor");
               }
               else
               {  
                  nodeRuleFileRoot.OwnerDocument.Save(m_strRuleFileNameFullPath);
                  this.DialogResult = DialogResult.OK;
                  this.Close();
               }

               Cursor.Current = oldCursor;
            }
            else if (result == DialogResult.No)
            {
               this.DialogResult = DialogResult.OK;
               this.Close();
            }
         }
         else
         {
            this.DialogResult = DialogResult.OK;
            this.Close();
         }
         
      }

      private void btnCancel_Click(object sender, System.EventArgs e)
      {
         this.Close();      
      }  
     
      private void RefreshTree()
      {
         string strKeyValue;
         string strNodeName;
         int    nNodeCount = 0;
         string strSelectedKey = "";

         if (ctlTree.SelectedNodes.Count > 0)
         {
            strSelectedKey = ctlTree.SelectedNodes[0].Key;
         }

         ctlTree.Nodes.Clear();
        
         foreach (XmlNode nodeCategory in nodeRuleFileRoot.ChildNodes)
         {
            if (nodeCategory.NodeType == XmlNodeType.Element)
            {
               strKeyValue = nNodeCount.ToString();
               strNodeName = nodeCategory.Attributes["name"].Value;
               nNodeCount++;
               UltraTreeNode  treeNodeCategory = new UltraTreeNode(strKeyValue, strNodeName);
               treeNodeCategory.DataKey = nodeCategory;
               treeNodeCategory.LeftImages.Add(0);
               ctlTree.Nodes.Add(treeNodeCategory);

               foreach (XmlNode nodeItem in nodeCategory.ChildNodes)
               {
                  if (nodeItem.NodeType == XmlNodeType.Element)
                  {
                     if (nodeItem.Name == "EmptyItem")
                     {
                        // Empty choice
                        strKeyValue = nNodeCount.ToString();
                        strNodeName = nodeItem.InnerText;
                        UltraTreeNode  treeNodeEmpty = new UltraTreeNode(strKeyValue, strNodeName);
                        treeNodeEmpty.DataKey = nodeItem;
                        treeNodeEmpty.LeftImages.Add(1);
                        treeNodeCategory.Nodes.Add(treeNodeEmpty);
                        nNodeCount++;
                     }
                     else if (nodeItem.Name == "Item")
                     {
                        // Regular item
                        string   strProductNumber = "";
                        
                        try
                        {
                           strProductNumber = nodeItem.Attributes["productId"].Value;                 
                        }
                        catch (Exception)
                        {
                           throw new ApplicationException("Error processing rules XML file. 'productId' attribute was not found.");
                        }

                        Product objProduct = eng.LoadProductFromProductNumber(strProductNumber);
                        
                        if (objProduct == null)
                        {
                           throw new ApplicationException("Error processing rules XML file. Unable to load product with part number: " + strProductNumber);
                        }

                        strKeyValue = nNodeCount.ToString(); //treeNodeCategory.Key + " " + objProduct.ProductId.ToString();
                        strNodeName = objProduct.ProductNumber + " - " + objProduct.Name;
                        UltraTreeNode  treeNodeItem = new UltraTreeNode(strKeyValue, strNodeName);
                        treeNodeItem.Text = strNodeName;
                        treeNodeItem.DataKey = nodeItem;
                        treeNodeItem.LeftImages.Add(1);
                        treeNodeCategory.Nodes.Add(treeNodeItem);
                        nNodeCount++;
         
                        int nRuleCount = 0;

                        foreach (XmlNode nodeRule in nodeItem.ChildNodes)
                        {
                           if (nodeRule.NodeType == XmlNodeType.Element)
                           {
                              // Add each rule item
                              strKeyValue = nNodeCount.ToString();

                              string strFriendlyName = "Unknown";

                              switch (nodeRule.Name)
                              {
                                 case "RequiresCategory":
                                    strFriendlyName = "Requires Category: ";
                                    break;
                                 
                                 case "RequiresItem":
                                    strFriendlyName = "Requires Item: ";
                                    break;
                                 
                                 case "NotCompatibleWith":
                                    strFriendlyName = "Not Compatible With: ";
                                    break;

                                 case "LinkedItem":
                                    strFriendlyName = "Linked Item: ";
                                    break;
                              }

                              strNodeName = strFriendlyName + nodeRule.InnerText;
                              UltraTreeNode  treeRuleItem = new UltraTreeNode(strKeyValue, strNodeName);
                              treeRuleItem.DataKey = nodeRule;
                              treeRuleItem.LeftImages.Add(2);
                              treeNodeItem.Nodes.Add(treeRuleItem);
                              nNodeCount++;
                              nRuleCount++;
                           }
                        }
                     }

                  }
               }
                           
            }
         } // end foreach

         if (strSelectedKey != "")
         {
            UltraTreeNode node = ctlTree.GetNodeByKey(strSelectedKey);

            if (node != null)
            {
               node.BringIntoView();
               ctlTree.ActiveNode = node;    
               node.Selected = true;
            }
         }

         EnableControls();
      }

      private void btnAdd_Click(object sender, System.EventArgs e)
      {
         AddItem();
      }

      private void btnModify_Click(object sender, System.EventArgs e)
      {
         ModifyItem();
      }

      private void mnuTreeList_Popup(object sender, System.EventArgs e)
      {
         Point ptCursor = Cursor.Position;
         
         ptCursor = ctlTree.PointToClient(ptCursor);
         UltraTreeNode  node = this.ctlTree.GetNodeFromPoint(new Point(ptCursor.X, ptCursor.Y));
         
         if (node != null)
         {
            ctlTree.ActiveNode = node;
            node.Selected = true;
         }

         EnableControls();
      }

      private void mnuModify_Click(object sender, System.EventArgs e)
      {
         ModifyItem();
      }

      private void mnuAdd_Click(object sender, System.EventArgs e)
      {
         AddItem();
      }

      private void AddItem()
      {
         AddChildItemDlg   dlg = new AddChildItemDlg();

         dlg.ShowDialog(this);    
         if (dlg.DialogResult == DialogResult.OK)
         {
            switch (dlg.ItemType)
            {
               case "Category":
                  AddCategory();
                  break;

               case "ChildProduct":
                  AddChildProduct();
                  break;

               case "Rule":
                  AddRule();
                  break;
            }
         }
      }

      private void AddCategory()
      {
         XmlNode           objNewCategory; 
         XmlAttribute      objAttribute;        
         ChildCategoryDlg  dlg = new ChildCategoryDlg();

         objNewCategory = nodeRuleFileRoot.OwnerDocument.CreateNode(XmlNodeType.Element, "Category", "");
         
         objAttribute = nodeRuleFileRoot.OwnerDocument.CreateAttribute("", "name", "");
         objAttribute.Value = "Untitled"; 
         objNewCategory.Attributes.Append(objAttribute);
         
         objAttribute = nodeRuleFileRoot.OwnerDocument.CreateAttribute("", "categoryId", "");
         objAttribute.Value = "UNTITLED_CATEGORY"; 
         objNewCategory.Attributes.Append(objAttribute);
         
         objAttribute = nodeRuleFileRoot.OwnerDocument.CreateAttribute("", "defaultSelection", "");
         objAttribute.Value = ""; 
         objNewCategory.Attributes.Append(objAttribute);

         objAttribute = nodeRuleFileRoot.OwnerDocument.CreateAttribute("", "type", "");
         objAttribute.Value = "SingleSelect"; 
         objNewCategory.Attributes.Append(objAttribute);
         
         dlg.CategoryNode = objNewCategory;
         dlg.ShowDialog(this);

         if (dlg.DialogResult == DialogResult.OK)
         {
            nodeRuleFileRoot.AppendChild(objNewCategory);
            RefreshTree();

            UltraTreeNode objNewNode = ctlTree.Nodes[ctlTree.Nodes.Count-1];
            objNewNode.BringIntoView();
            ctlTree.ActiveNode = objNewNode;            
            objNewNode.Selected = true;     
            bNeedSave = true;
            EnableControls();
         }  
      }

      private void AddChildProduct()
      {
         if (ctlTree.Nodes.Count == 0)
         {
               MessageBox.Show(this, "Please add a category before adding products.");
         }
         else if (ctlTree.SelectedNodes.Count > 0)
         {
            ChildProductDlg   dlg = new ChildProductDlg();
            XmlNode           objParentNode = null;
            XmlNode           objNewProductNode = null;
            XmlAttribute      objAttribute;        
            XmlDocument       objDocument;
            string            strParentKey = "";

            XmlNode  node = (XmlNode)ctlTree.SelectedNodes[0].DataKey;

            if (node.Name.ToLower() == "category")
            {
               objParentNode = node;
               strParentKey = ctlTree.SelectedNodes[0].Key;
            }
            else if (node.Name.ToLower() == "item")
            {
               objParentNode = node.ParentNode;
               strParentKey = ctlTree.SelectedNodes[0].Parent.Key;
            }
            else
            {
               objParentNode = node.ParentNode.ParentNode;
               strParentKey = ctlTree.SelectedNodes[0].Parent.Parent.Key;
            }

            objDocument = objParentNode.OwnerDocument;
            objNewProductNode = objDocument.CreateElement("", "Item", "");
            objParentNode.AppendChild(objNewProductNode);
         
            objAttribute = objDocument.CreateAttribute("", "productId", "");
            objAttribute.Value = ""; 
            objNewProductNode.Attributes.Append(objAttribute);
            
            objAttribute = objDocument.CreateAttribute("", "autoAdd", "");
            objAttribute.Value = "false"; 
            objNewProductNode.Attributes.Append(objAttribute);
        
            objAttribute = objDocument.CreateAttribute("", "allowDiscounting", "");
            objAttribute.Value = "true"; 
            objNewProductNode.Attributes.Append(objAttribute);

            objAttribute = objDocument.CreateAttribute("", "ruleFileName", "");
            objAttribute.Value = ""; 
            objNewProductNode.Attributes.Append(objAttribute);
        
            dlg.InputNode = objNewProductNode;
            dlg.Engine = eng;
            dlg.ShowDialog(this);
         
            if (dlg.DialogResult == DialogResult.OK)
            {
               bNeedSave = true;
               objNewProductNode.ParentNode.ReplaceChild(dlg.OutputNode, objNewProductNode);
               RefreshTree(); 
            
               // Find the parent node and select the newly added child
               UltraTreeNode objParentTreeNode = ctlTree.GetNodeByKey(strParentKey); 
               
               if (objParentTreeNode != null)
               {
                  UltraTreeNode objNewNode = null;

                  if (objParentTreeNode.Nodes.Count == 0)
                  {
                     objNewNode = objParentTreeNode;
                  
                  }
                  else
                  {
                     objNewNode = objParentTreeNode.Nodes[objParentTreeNode.Nodes.Count-1];
                  }
               
                  objNewNode.BringIntoView();
                  ctlTree.ActiveNode = objNewNode;            
                  objNewNode.Selected = true;
               }
            }
            else
            {
               // We're not adding the new item
               objParentNode.RemoveChild(objNewProductNode);
            }
         }
      }

      private void AddRule()
      {
         RuleDlg           dlg = new RuleDlg();
         XmlNode           objParentDataNode = null;
         string            strParentKey = "";
         XmlNode           objNewRuleNode = null;
         XmlDocument       objDocument;

         if (ctlTree.SelectedNodes.Count > 0)
         {
            // Examine what is currently selected and decide where to place the new node
            XmlNode  node = (XmlNode)ctlTree.SelectedNodes[0].DataKey;

            if (node.Name.ToLower() == "category")
            {
               if (node.ChildNodes.Count > 0)
               {
                  objParentDataNode = node.ChildNodes[0];
                  strParentKey = ctlTree.SelectedNodes[0].Nodes[0].Key;
               }
            }
            else if (node.Name.ToLower() == "item")
            {
               objParentDataNode = node;
               strParentKey = ctlTree.SelectedNodes[0].Key;
            }
            else
            {
               objParentDataNode = node.ParentNode;
               strParentKey = ctlTree.SelectedNodes[0].Parent.Key;
            }

            if (objParentDataNode == null)
            {
               MessageBox.Show(this, "Please add a child product before adding rules.");
            }
            else
            {
               objDocument = objParentDataNode.OwnerDocument;
               objNewRuleNode = objDocument.CreateElement("", "RequiresCategory", "");
               objParentDataNode.AppendChild(objNewRuleNode);
                  
               dlg.InputRuleNode = objNewRuleNode;
               dlg.Engine = eng;
               dlg.ShowDialog(this);
         
               if (dlg.DialogResult == DialogResult.OK)
               {
                  bNeedSave = true;
                  objParentDataNode.ReplaceChild(dlg.OutputRuleNode, objNewRuleNode);
                  RefreshTree();              

                  // Find the parent node and select the newly added child
                  UltraTreeNode objParentTreeNode = ctlTree.GetNodeByKey(strParentKey); 
               
                  if (objParentTreeNode != null)
                  {
                     UltraTreeNode objNewNode = objParentTreeNode.Nodes[objParentTreeNode.Nodes.Count-1];
                     objNewNode.BringIntoView();
                     ctlTree.ActiveNode = objNewNode;            
                     objNewNode.Selected = true;
                  }
               }
               else
               {
                  // We're not adding the new item
                  objParentDataNode.RemoveChild(objNewRuleNode);
               }
            } 
         }

      }

      private void ModifyItem()
      {
         if (ctlTree.SelectedNodes.Count > 0)
         {
            XmlNode  node = (XmlNode)ctlTree.SelectedNodes[0].DataKey;

            if (node.Name.ToLower() == "category")
            {
               ModifyCategory(node);
            }
            else if ((node.Name.ToLower() == "item") || (node.Name.ToLower() == "emptyitem"))
            {
               ModifyChildProduct(node);
            }
            else
            {
               ModifyRule(node);
            }
         }   
      }

      private void RemoveItem()
      {
         if (ctlTree.SelectedNodes.Count > 0)
         {
            XmlNode  node = (XmlNode)ctlTree.SelectedNodes[0].DataKey;

            if (node.Name.ToLower() == "category")
            {
               RemoveCategory(node);
            }
            else if ((node.Name.ToLower() == "item") || (node.Name.ToLower() == "emptyitem"))
            {
               RemoveChildProduct(node);
            }
            else
            {
               RemoveRule(node);
            }
         }   
      }

      private void SelectPreviousTreeNode()
      {
         UltraTreeNode objSelectedNode = ctlTree.SelectedNodes[0];

         ctlTree.SelectedNodes.Clear();

         if (objSelectedNode.HasSibling(NodePosition.Previous))
         {
            // Select the previous sibling
            UltraTreeNode objPrevNode = objSelectedNode.GetSibling(NodePosition.Previous);
            objPrevNode.Selected = true;
         }
         else if (objSelectedNode.Parent != null)
         {
            // Select the parent
            objSelectedNode.Parent.Selected = true;
         }
         else
         {
            // Select the first node
            if (ctlTree.Nodes.Count > 0)
            {
               ctlTree.Nodes[0].Selected = true;  
            }
         }
      }

      private void MoveItemUp()
      {
         if (ctlTree.SelectedNodes.Count > 0)
         {
            UltraTreeNode  guiNode = ctlTree.SelectedNodes[0];
            XmlNode  node = (XmlNode)guiNode.DataKey;
            XmlNode  nodePrev = node.PreviousSibling;
            XmlNode  nodeComment = null;
            TreeNodesCollection  objSiblingGuiNodeCollection;
            XmlNode  nodeParent = null;

            if (guiNode.Parent == null)
            {  
               // We're moving a root level category
               nodeParent = node.OwnerDocument.ChildNodes[1];
               objSiblingGuiNodeCollection = ctlTree.Nodes;
            }
            else
            {
               // We're moving a regular node
               nodeParent = node.ParentNode;
               objSiblingGuiNodeCollection = guiNode.ParentNodesCollection;
            }                 
               
            if (nodePrev.NodeType == XmlNodeType.Comment)
            {
               nodeComment = nodePrev;
               nodePrev = nodePrev.PreviousSibling;
            }

            if (nodePrev != null)
            {
               // Move the data node
               XmlNode child = nodeParent.RemoveChild(node);

               if (nodeComment != null)
               {
                  XmlNode childComment = nodeParent.RemoveChild(nodeComment);

                  nodeParent.InsertBefore(child, nodePrev);

                  if (nodeComment != null)
                     nodeParent.InsertBefore(childComment, child);
               }
               else
               {
                  nodeParent.InsertBefore(child, nodePrev);
               }        

               // Move the GUI node
               int      nPos = guiNode.Index;

               objSiblingGuiNodeCollection.RemoveAt(nPos);
               objSiblingGuiNodeCollection.Insert(nPos-1, guiNode);
               ctlTree.ActiveNode = guiNode;
            }

            bNeedSave = true;
         }   
      }

      private void MoveItemDown()
      {
         if (ctlTree.SelectedNodes.Count > 0)
         {
            UltraTreeNode  guiNode = ctlTree.SelectedNodes[0];
            XmlNode  node = (XmlNode)guiNode.DataKey;
            XmlNode  nodeNext = node.NextSibling;
            XmlNode  nodeComment = null;
            TreeNodesCollection  objSiblingGuiNodeCollection;
            XmlNode  nodeParent = null;

            if (guiNode.Parent == null)
            {  
               // We're moving a root level category
               nodeParent = node.OwnerDocument.ChildNodes[1];
               objSiblingGuiNodeCollection = ctlTree.Nodes;
            }
            else
            {
               // We're moving a regular node
               nodeParent = node.ParentNode;
               objSiblingGuiNodeCollection = guiNode.ParentNodesCollection;
            }                 
               
            if (nodeNext.NodeType == XmlNodeType.Comment)
            {
               nodeComment = nodeNext;
               nodeNext = nodeNext.NextSibling;
            }

            if (nodeNext != null)
            {
               // Move the data node
               XmlNode child = nodeParent.RemoveChild(node);

               if (nodeComment != null)
               {
                  XmlNode childComment = nodeParent.RemoveChild(nodeComment);

                  nodeParent.InsertAfter(child, nodeNext);

                  if (nodeComment != null)
                     nodeParent.InsertAfter(childComment, child);
               }
               else
               {
                  nodeParent.InsertAfter(child, nodeNext);
               }        

               // Move the GUI node
               int      nPos = guiNode.Index;

               objSiblingGuiNodeCollection.RemoveAt(nPos);
               objSiblingGuiNodeCollection.Insert(nPos+1, guiNode);
               ctlTree.ActiveNode = guiNode;
            }

            bNeedSave = true;
         }   
      }

      private void RemoveCategory(XmlNode node)
      {
         if (DialogResult.Yes == MessageBox.Show(this, "Are you sure that you want to remove this category?", "QuoteAdvantage Editor", MessageBoxButtons.YesNo))
         {
            SelectPreviousTreeNode();   
            node.ParentNode.RemoveChild(node);
            RefreshTree();
            bNeedSave = true;
         }
      }

      private void RemoveChildProduct(XmlNode node)
      {
         SelectPreviousTreeNode();   
         node.ParentNode.RemoveChild(node);
         RefreshTree();
         bNeedSave = true;
      }

      private void RemoveRule(XmlNode node)
      {
         SelectPreviousTreeNode();   
         node.ParentNode.RemoveChild(node);
         RefreshTree();
         bNeedSave = true;
      }

      private void ModifyCategory(XmlNode node)
      {
         ChildCategoryDlg dlg = new ChildCategoryDlg();
         dlg.CategoryNode = node;
         dlg.ShowDialog(this);

         if (dlg.DialogResult == DialogResult.OK)
         {
            RefreshTree(); 
            bNeedSave = true;
         }
      }

      private void ModifyChildProduct(XmlNode node)
      {
         Cursor.Current = Cursors.WaitCursor;
         ChildProductDlg dlg = new ChildProductDlg();

         dlg.Engine = eng;
         dlg.InputNode = node;
         dlg.ShowDialog(this);

         if (dlg.DialogResult == DialogResult.OK)
         {
            node.ParentNode.ReplaceChild(dlg.OutputNode, node);
            RefreshTree(); 
            bNeedSave = true;
         }
      }

      private void ModifyRule(XmlNode node)
      {
         RuleDlg dlg = new RuleDlg();

         dlg.Engine = eng;
         dlg.InputRuleNode = node;
         dlg.ShowDialog(this);
         
         if (dlg.DialogResult == DialogResult.OK)
         {
            node.ParentNode.ReplaceChild(dlg.OutputRuleNode, node);
            RefreshTree(); 
            bNeedSave = true;
         }
      }

      private void EnableControls()
      {
         bool  bAllowMoveUp = false;
         bool  bAllowMoveDown = false;
         bool  bAllowRemove = false;
         bool bAllowNestedItems = false;

         UltraTreeNode  objSelectedNode = null;
         
         if (ctlTree.SelectedNodes.Count > 0)
         {
            bAllowRemove = true;
            objSelectedNode = ctlTree.SelectedNodes[0];
            TreeNodesCollection  objSiblingCollection = ctlTree.Nodes; 

            if (objSelectedNode.Parent != null)
               objSiblingCollection = objSelectedNode.Parent.Nodes;

            if (objSelectedNode.Index > 0)
            {
               bAllowMoveUp = true;
            }

            if (objSelectedNode.Index < (objSiblingCollection.Count-1))
            {
               bAllowMoveDown = true;
            }

            XmlNode  node = (XmlNode)ctlTree.SelectedNodes[0].DataKey;

            if (node.Attributes["ruleFileName"] != null)
            {
               if (node.Attributes["ruleFileName"].Value != "")
               {
                  bAllowNestedItems = true;
               }
            }                
         }
         
         mnuModify.Enabled = bAllowRemove;
         mnuNestedItems.Enabled = bAllowNestedItems;

         mnuRemove.Enabled = bAllowRemove;
         mnuMoveUp.Enabled = bAllowMoveUp;
         mnuMoveDown.Enabled = bAllowMoveDown;

         btnRemove.Enabled = bAllowRemove;
         btnModify.Enabled = bAllowRemove;
      }

      private void mnuRemove_Click(object sender, System.EventArgs e)
      {
         RemoveItem();
      }

      private void btnRemove_Click(object sender, System.EventArgs e)
      {
         RemoveItem();
      }

      private void mnuMoveUp_Click(object sender, System.EventArgs e)
      {
         MoveItemUp();
      }

      private void mnuMoveDown_Click(object sender, System.EventArgs e)
      {
         MoveItemDown();
      }

      private void ctlTree_Click(object sender, System.EventArgs e)
      {
         EnableControls();
      }

      private void ctlTree_DoubleClick(object sender, System.EventArgs e)
      {
         // In some circumstances, perform a Modify in response to a double-click
         UltraTreeNode  objSelectedNode = ctlTree.ActiveNode;

         if (objSelectedNode != null)
         {
            if ((objSelectedNode.Nodes.Count > 0) && objSelectedNode.Expanded)
            {
               ModifyItem();
               ctlTree.ActiveNode.Expanded = true;
            }
            else if (objSelectedNode.Nodes.Count == 0)
            {
               ModifyItem();   
               ctlTree.ActiveNode.Expanded = true;
            }
            else
            {
               objSelectedNode.Expanded = true;
            }
         }
      }

      private void mnuNestedItems_Click(object sender, System.EventArgs e)
      {
         ModifyChildProducts();
      }    
      
      private void ModifyChildProducts()
      {
         Cursor oldCursor = Cursor.Current;
         Cursor.Current = Cursors.WaitCursor; 

         XmlNode objSelectedNode = (XmlNode)ctlTree.SelectedNodes[0].DataKey;
         string strProductId = objSelectedNode.Attributes["productId"].Value;
         Product objParentProduct = eng.LoadProductFromProductNumber(strProductId);
         
         if (objParentProduct == null)
         {
            MessageBox.Show(this, "This product could not be loaded from the Microsoft CRM Product Catalog.", "QuoteAdvantage Editor");
         }
         else
         {
            ProductCustomizeDlg  dlg = new ProductCustomizeDlg();
            string               strNestedRuleFileName = "";
            
            if (objSelectedNode.Attributes["ruleFileName"] != null)
            {
               strNestedRuleFileName = objSelectedNode.Attributes["ruleFileName"].Value;
            }

            if (strNestedRuleFileName == "")
            {
               MessageBox.Show(this, "This product does not have a rule file name \r\nspecified for managing child products.", "Unable to Load Child Products");
            }
            else
            {
               FileInfo info = new FileInfo(m_strRuleFileNameFullPath);
               string strNestedRuleFileNameFullPath = info.DirectoryName + "\\" + strNestedRuleFileName;
            
               if (!File.Exists(strNestedRuleFileNameFullPath))
               {
                  // Create a new rule file
                  CreateNewRuleFile(strNestedRuleFileNameFullPath);
               }

               if (!File.Exists(strNestedRuleFileNameFullPath))
               {
                  MessageBox.Show(this, strNestedRuleFileNameFullPath + " could not be found.", "QuoteAdvantage Editor");
               }
               else
               {
                  dlg.RuleFileName = strNestedRuleFileNameFullPath;
                  dlg.ParentProduct = objParentProduct;
                  dlg.Engine = eng;

                  Cursor.Current = oldCursor;

                  try
                  {
                     dlg.ShowDialog(this);

                     if (dlg.DialogResult == DialogResult.OK)
                     {
                     }
                  }
                  catch (Exception ex)
                  {
                     MessageBox.Show(this, ex.Message, "QuoteAdvantage Editor");
                  }
               }
            }
         } // end if - Product is available
      }               

      private void CreateNewRuleFile(string strRuleFileNameFullPath)
      {
         TextWriter  objFile = new StreamWriter(strRuleFileNameFullPath);

         objFile.WriteLine(@"<?xml version=""1.0"" encoding=""utf-8"" ?>");
         objFile.WriteLine(@"<ConfigurationData>");
         objFile.WriteLine(@"   <Category name=""Untitled Category"" categoryId=""UNTITLED_CATEGORY"">"); 
         objFile.WriteLine(@"   </Category>");
         objFile.WriteLine(@"</ConfigurationData>");
         objFile.Close();
      }
  
	} // end class
}
